#ifndef	__mesh_H__
#define	__mesh_H__

#include "rendPlatform.hpp"
#include "rendVisual.hpp"
#include "rendVectorArray.hpp"
#include "rendAttrBuffer.hpp"

#include <stdio.h>
#include <vector>
#include <string>


namespace rend
{

class MeshIndexed : public Visual
{
public:

#if 1
	typedef	unsigned short	Index;								// vertex indexation type
#else
	typedef	unsigned int	Index;
#endif

	MeshIndexed();
	MeshIndexed(const MeshIndexed& src);

	~MeshIndexed();

	static const std::string attr_semantics_position;
	static const std::string attr_semantics_normal;
	static const std::string attr_semantics_blend_weights;
	static const std::string attr_semantics_texcoord;
	static const std::string attr_semantics_index;

	static const AttrElementType attr_element_index;

	void					setRegister(AttrBuffer16::Register*);
	AttrBuffer16::Register*	getRegister() const;

	void					setNumVertBuffers(const unsigned num);
	bool					setVertexBuffer(const std::string&, const unsigned index);
	bool					setIndexBuffer(const std::string&);

	unsigned				getNumVertBuffers() const;
	const std::string&		getVertexBuffer(const unsigned index) const;
	const std::string&		getIndexBuffer() const;

	unsigned				getNumVertices() const;
	unsigned				getNumTriangles() const;

	virtual void			draw();
	virtual void			drawWire();

	// file io, native format
	bool					load(
								FILE *,
								const std::string& registration_name);

	bool					save(
								FILE *) const;
	bool					save_texcoord(
								FILE *) const;

	static bool				load(
								const std::string& filename,
								std::vector< MeshIndexed >& meshes,
								AttrBuffer16::Register* reg_buf);

	static bool				save(
								const std::string& filename,
								const std::vector< MeshIndexed >& meshes);
	static bool				save_texcoord(
								const std::string& filename,
								const std::vector< MeshIndexed >& meshes);

	// file io, 3ds format
	static bool				load3ds_smooth(
								const std::string& filename,
								std::vector< MeshIndexed >& meshes,
								AttrBuffer16::Register* reg_buf);

	static bool				load3ds_nosmooth(
								const std::string& filename,
								std::vector< MeshIndexed >& meshes,
								AttrBuffer16::Register* reg_buf);

	// file io, age format
	static bool				loadAge(
								const std::string& filename,
								std::vector< MeshIndexed >& meshes,
								AttrBuffer16::Register* reg_buf);

	// upload mesh's current attribute buffers to the server; otherwise done automatically on first use
	void					upload() const;

private:

	AttrBuffer16::Register*				m_reg_buf;

	std::vector< std::string >			m_vtx;					// names of vertex attribute buffers
	std::string							m_tri;					// name of index buffer
};


inline void
MeshIndexed::setRegister(
	AttrBuffer16::Register* reg)
{
	assert(reg);

	m_reg_buf = reg;
}


inline AttrBuffer16::Register*
MeshIndexed::getRegister() const
{
	return m_reg_buf;
}


inline void
MeshIndexed::setNumVertBuffers(
	const unsigned num)
{
	m_vtx.resize(num);

	for (std::vector< std::string >::iterator it = m_vtx.begin(); it != m_vtx.end(); ++it)
		it->clear();
}


inline bool
MeshIndexed::setVertexBuffer(
	const std::string& name,
	const unsigned index)
{
	assert(index < m_vtx.size());

	m_vtx[index] = name;
	return true;
}


inline bool
MeshIndexed::setIndexBuffer(
	const std::string& name)
{
	m_tri = name;
	return true;
}


inline unsigned
MeshIndexed::getNumVertBuffers() const
{
	return m_vtx.size();
}


inline const std::string&
MeshIndexed::getVertexBuffer(
	const unsigned index) const
{
	assert(index < m_vtx.size());

	return m_vtx[index];
}


inline const std::string&
MeshIndexed::getIndexBuffer() const
{
	return m_tri;
}


inline unsigned
MeshIndexed::getNumVertices() const
{
	for (std::vector< std::string >::const_iterator it = m_vtx.begin(); it != m_vtx.end(); ++it)
	{
		const std::string& name = *it;

		if (name.empty())
			continue;

		const AttrBuffer16* attr_buffer = m_reg_buf->seek(name);

		if (attr_buffer && attr_buffer->getBufferType() == AttrBuffer16::BUFFER_TYPE_VERTEX && attr_buffer->getBufferLength())
			return attr_buffer->getBufferLength();
	}

	return 0;
}


inline unsigned
MeshIndexed::getNumTriangles() const
{
	if (m_tri.length())
	{
		const AttrBuffer16* attr_buffer = m_reg_buf->seek(m_tri);

		if (attr_buffer && attr_buffer->getBufferType() == AttrBuffer16::BUFFER_TYPE_INDEX)
			return attr_buffer->getBufferLength();
	}

	return 0;
}

} // namespace rend

#endif // __mesh_H__
